package com.lazy.example.clientfault;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import static java.util.concurrent.Executors.newScheduledThreadPool;

/**
 * 二进制传输客户端
 * Created by lazy on 7/13/16.
 */
public class ByteBufClient {
    private static final Logger logger = LoggerFactory.getLogger(ByteBufClient.class);

    private String host;
    private int port;

    private EventLoopGroup group;
    private Bootstrap bootstrap;

    protected ChannelHandler handler;

    private int seq = 0;

    // TODO: is only one channel
    private Channel channel;

    public ByteBufClient(String host, int port, ChannelHandler handler){
        this.host = host;
        this.port = port;
        this.handler = handler;
    }

    public void init() {
        group = new NioEventLoopGroup();
        bootstrap = new Bootstrap();
        bootstrap.group(group)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                .channel(NioSocketChannel.class)
                .handler(new ByteBufClientInitializer(getHandler()));
    }

    /**
     * 设置本地的链接ip地址
     * @param localHost
     */
    public void setLocalHost(String localHost) {
        bootstrap.localAddress(localHost, 0);
    }

    public ChannelHandler getHandler(){
        return handler;
    }
    public void setHandler(ChannelHandler handler){
        this.handler = handler;
    }

    public Channel getChannel() {
        return channel;
    }

    /** when connect it should be disconnect by caller */
    public Channel connect() {
        // Start the connection attempt.
        if (bootstrap != null) {
            try{
                channel = bootstrap.connect(host, port).sync().channel();
                logger.info("Connected to {} ", channel);

                // TODO: 对客户端的连接是否需要管理, 暂时只有一个channel
                return channel;
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        return null;
    }

    public ChannelFuture write(Object msg) {
        if (channel != null && channel.isActive() && channel.isWritable()) {
            return channel.writeAndFlush(msg);
        } else {
            return null;
        }
    }

    public ChannelFuture write(Channel ch, Object msg) {
        return ch.writeAndFlush(msg);
    }

    public void disconnect() {
        if (channel != null) {
            channel.disconnect();
        }
    }

    public void shutdown() {
        if (group != null) {
            group.shutdownGracefully();
        }
    }

    public String getTestData() {
        return String.format("seq %03d\n", seq++);
    }

    public static void main(String[] args) throws Exception {
        String host = "192.168.0.233";
        int port = 8033;
        ByteBufClient client = new ByteBufClient(host, port, new ByteBufBaseHandler());
        client.init();
        client.connect();
        //byte[] array = "hello\n".getBytes();
        //ByteBuf buf = ByteBufAllocator.DEFAULT.buffer().writeBytes(array);
        //client.write(Unpooled.wrappedBuffer(array));
        //logger.info("send: {}", ByteBufUtil.hexDump(buf));

        ScheduledExecutorService scheduledPool = newScheduledThreadPool(2);
        scheduledPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
               byte[] array = client.getTestData().getBytes();
                logger.info("send: {}", ByteBufUtil.hexDump(array));
                ChannelFuture future = client.write(Unpooled.wrappedBuffer(array));
                if (future != null) {
                    future.addListener(new ChannelFutureListener() {
                        @Override
                        public void operationComplete(ChannelFuture future) throws Exception {
                            logger.info("result: {}", future.isSuccess());
                        }
                    });
                } else {
                    logger.error("send error");
                }
            }
        }, 0, 3, TimeUnit.SECONDS);

    }

}
